package com.shop.cereshop.app.tencent.im.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shop.cereshop.app.dao.buyer.CereBuyerUserDAO;
import com.shop.cereshop.app.dao.tim.transfer.TransferOrderMapper;
import com.shop.cereshop.app.dao.tim.transfer.TransferReceiveRecordMapper;
import com.shop.cereshop.app.dao.tim.transfer.TransferRefundRecordMapper;
import com.shop.cereshop.app.dao.wallet.WalletTransactionDAO;
import com.shop.cereshop.app.exception.BusinessException;
import com.shop.cereshop.app.tencent.im.delay.constant.BusinessType;
import com.shop.cereshop.app.tencent.im.delay.constant.TaskType;
import com.shop.cereshop.app.tencent.im.delay.model.DelayedTask;
import com.shop.cereshop.app.tencent.im.delay.service.RDelayedQueueService;
import com.shop.cereshop.app.tencent.im.model.transfer.*;
import com.shop.cereshop.app.tencent.im.service.TransferOrderService;
import com.shop.cereshop.app.tencent.im.pay.TimWalletPayService;
import com.shop.cereshop.app.utils.SnowflakeIdFactory;
import com.shop.cereshop.commons.constant.CoReturnFormat;
import com.shop.cereshop.commons.domain.wallet.WalletTransaction;
import com.shop.cereshop.commons.enums.PaymentModeEnum;
import com.shop.cereshop.commons.enums.RefundTypeEnum;
import com.shop.cereshop.commons.enums.TransactionTypeEnum;
import com.shop.cereshop.commons.result.Result;
import com.shop.cereshop.commons.tencent.im.enums.im.ActionStatus;
import com.shop.cereshop.commons.tencent.im.enums.im.MsgTypeEnum;
import com.shop.cereshop.commons.tencent.im.enums.transfer.TransferOrderStatusEnum;
import com.shop.cereshop.commons.tencent.im.model.msg.data.CustomMsgData;
import com.shop.cereshop.commons.tencent.im.model.msg.dto.MsgRequestDTO;
import com.shop.cereshop.commons.tencent.im.model.response.SendGroupMsgResponse;
import com.shop.cereshop.commons.tencent.im.model.response.SendMsgResponse;
import com.shop.cereshop.commons.tencent.im.model.response.TIMBaseResponse;
import com.shop.cereshop.commons.tencent.im.service.TimMsgService;
import com.shop.cereshop.commons.utils.redis.RedissonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.shop.cereshop.commons.tencent.im.constant.RedisCache.CACHE_TRANSFER_ORDER_RECEIVE_LOCK_PREFIX;

/**
 * @author zdd
 * @version 1.0
 * @description: 腾讯IM-转账接口
 * @date 2025/9/22 14:36
 */
@Service
@Slf4j
public class TransferOrderServiceImpl implements TransferOrderService {

    @Resource
    private TransferOrderMapper transferOrderMapper;
    @Resource
    private TransferReceiveRecordMapper transferReceiveRecordMapper;
    @Resource
    private TransferRefundRecordMapper transferRefundRecordMapper;
    @Resource
    private TimMsgService timMsgService;
    @Resource
    private TimWalletPayService timWalletPayService;
    @Resource
    private RDelayedQueueService delayedQueueService;
    @Resource
    private CereBuyerUserDAO buyerUserDAO;
    @Resource
    private WalletTransactionDAO walletTransactionDAO;

    /**
     * 锁等待时间
     */
    @Value("${red-packet.lock.wait-time:3}")
    private long lockWaitTime;
    /**
     * 锁自动续期时间
     */
    @Value("${red-packet.lock.lease-time:1}")
    private long lockLeaseTime;
    /**
     * 锁时间单位
     */
    @Value("#{T(java.util.concurrent.TimeUnit).valueOf('${red-packet.lock.time-unit:SECONDS}')}")
    private TimeUnit lockTimeUnit;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<TransferOrderVO> create(CreateTransferOrderParam param) {
        // 生成转账单号、保存转账订单数据
        String transferId = String.valueOf(SnowflakeIdFactory.generateId());
        String orderId = "TO" + transferId;
        String receiverName = buyerUserDAO.getUserNameById(Long.parseLong(param.getReceiverId()));
        TransferOrder transferOrder = param.covertToTransferOrder();
        transferOrder.setTransferId(transferId);
        transferOrder.setOrderId(orderId);
        transferOrder.setReceiverName(receiverName);
        int insert = transferOrderMapper.insert(transferOrder);
        if (insert > 0) {
            log.info("转账订单创建成功, transferId: {}", transferId);
            TransferOrderVO orderVO = transferOrder.covertToVO();
            orderVO.setOrderId(orderId);
            orderVO.setTransactionType(TransactionTypeEnum.TRANSFER_ORDER_PAY.getCode());
            return Result.success(orderVO);
        }
        return Result.failed("转账订单创建失败");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Void> send(SendTransferOrderParam param) {
        String orderId = param.getOrderId();
        LambdaQueryWrapper<TransferOrder> queryWrapper = new QueryWrapper<TransferOrder>().lambda()
                .eq(TransferOrder::getOrderId, orderId);
        TransferOrder transferOrder = transferOrderMapper.selectOne(queryWrapper);
//        TransferOrder transferOrder = transferOrderMapper.selectById(transferId);
        if (transferOrder == null) {
            log.warn("发送转账时，转账订单不存在, orderId: {}", orderId);
            return Result.custom(CoReturnFormat.FAIL, "转账订单不存在");
        }
        if (transferOrder.getStatus() > 3) {
            return Result.custom(CoReturnFormat.FAIL, "当前转账订单已发送过，请勿重复发送！");
        }
        long buyerUserId = Long.parseLong(transferOrder.getSenderId());
        BigDecimal orderAmount = transferOrder.getAmount();

        // 校验支付结果
        Result<Void> payResult = verifyPayResult(param.getPayMethod(), buyerUserId, transferOrder.getTransferId(), orderId, orderAmount);
        if (!CoReturnFormat.SUCCESS.equals(payResult.getCode())) {
                log.warn("转账订单扣款失败, orderId: {}", orderId);
                // 更新转账订单状态为支付失败
                transferOrder.setStatus(TransferOrderStatusEnum.PAY_FAILED.getCode());
                transferOrderMapper.updateById(transferOrder);
            return payResult;
        }

        // 设置支付方式和支付时间、更新转账订单状态为待领取
        LocalDateTime nowTime = LocalDateTime.now();
        transferOrder.setPayMethod(param.getPayMethod());
        transferOrder.setSendTime(nowTime);
        transferOrder.setPayTime(nowTime);
        transferOrder.setExpireTime(nowTime.plusHours(24));
        transferOrder.setStatus(TransferOrderStatusEnum.PENDING_RECEIVED.getCode());
        MsgRequestDTO requestDTO = transferOrder.covertToMsgRequestDTO();
        CustomMsgData msgData = transferOrder.covertToCustomMsgData();

        boolean isSendSuccess = false;
        try {
            if (StringUtils.isNotBlank(transferOrder.getGroupId())) {
                SendGroupMsgResponse response = timMsgService.sendGroupMsg(MsgTypeEnum.CUSTOM, msgData, requestDTO);
                if (ActionStatus.OK.getStatus().equals(response.getActionStatus())) {
                    isSendSuccess = true;
                    transferOrder.setMsgSeq(response.getMsgSeq());
                }
            } else {
                SendMsgResponse response = timMsgService.sendC2cMsg(MsgTypeEnum.CUSTOM, msgData, requestDTO);
                if (ActionStatus.OK.getStatus().equals(response.getActionStatus())) {
                    isSendSuccess = true;
                    transferOrder.setMsgId(response.getMsgId());
                    transferOrder.setMsgKey(response.getMsgKey());
                }
            }
            String typeName = StringUtils.isNotBlank(transferOrder.getGroupId()) ? "群聊转账订单" : "单聊转账订单";
            if (isSendSuccess) {
                log.info("{}发送成功，接收者ID: {}, 转账单号: {}", typeName, transferOrder.getReceiverId(), orderId);
                transferOrderMapper.updateById(transferOrder);

                // 添加到延迟队列，24小时后检查是否需要退款，触发红包过期定时取消任务
                long delaySeconds = java.time.Duration.between(nowTime, transferOrder.getExpireTime()).getSeconds();
                DelayedTask task = new DelayedTask(transferOrder.getTransferId(), TaskType.TRANSFER_ORDER, transferOrder);
                delayedQueueService.addTask(BusinessType.TRANSFER_ORDER_EXPIRE_REFUND, task, delaySeconds);
                return Result.success();
            } else {
                // 发送失败需要恢复用户钱包余额
                timWalletPayService.addWalletBalance(buyerUserId, orderId, orderAmount,
                        TransactionTypeEnum.TRANSFER_ORDER_REFUND.getCode(), "转账消息发送失败，回退用户钱包余额");

                log.warn("{}发送失败，接收者ID: {}, 转账单号: {}", typeName, transferOrder.getReceiverId(), orderId);
                return Result.custom(CoReturnFormat.FAIL, "系统繁忙，请稍后再试!");
            }
        } catch (Exception e) {
            log.error("发送转账订单消息失败, orderId: {}", orderId, e);
            throw new BusinessException("发送转账订单消息失败: " + e.getMessage());
        }
    }

    /**
     * 验证支付结果
     *
     * @param payMethod   支付方式
     * @param buyerUserId 用户ID
     * @param transferId  转账订单ID
     * @param orderId     订单ID
     * @param amount      转账金额
     * @return 支付结果
     */
    private Result<Void> verifyPayResult(Integer payMethod, long buyerUserId, String transferId, String orderId, BigDecimal amount) {
        // 根据支付方式和红包单号，校验是否已经支付成功（钱包、支付宝、微信分别校验）
        if (PaymentModeEnum.WALLET_PAY.getCode().equals(payMethod)) {
            LambdaQueryWrapper<WalletTransaction> queryWrapper = new QueryWrapper<WalletTransaction>().lambda()
                    .eq(WalletTransaction::getOrderId, orderId)
                    .eq(WalletTransaction::getBuyerUserId, buyerUserId);
            WalletTransaction transaction = walletTransactionDAO.selectOne(queryWrapper);
            if (transaction == null) {
                log.warn("发送转账订单时，没有查到钱包支付流水, transferId: {}", transferId);
                return Result.custom(CoReturnFormat.FAIL, "钱包支付结果异常，请先支付！");
            }
            boolean isAmountValid = (transaction.getAmount().compareTo(amount) == 0)
                    && (transaction.getBalanceBefore().compareTo(amount) >= 0);
            if (!isAmountValid) {
                log.warn("发送转账订单时，钱包支付结果异常, transferId: {}", transferId);
                return Result.custom(CoReturnFormat.FAIL, "钱包支付结果异常，请先支付！");
            }

        } else {
//            // 验证支付宝支付结果
//            AlipayTradeQueryResponse queryResponse = AlipayUtils.queryPayResult(orderId);
//            if (!AlipayUtils.isSuccess(queryResponse)) {
//                log.warn("发送红包时，支付宝支付结果异常, packetId: {}", packetId);
//            }
            // todo 微信、支付宝 暂不支持
            return Result.custom(CoReturnFormat.FAIL, "暂不支持该支付方式，请选择其他支付方式！");
        }
        return Result.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Object> receive(TransferOrderDTO transferDTO) {
        String transferId = transferDTO.getTransferId();
        String receiverId = transferDTO.getReceiverId();
        // 获取分布式锁对象
        RLock lock = RedissonUtil.getLock(CACHE_TRANSFER_ORDER_RECEIVE_LOCK_PREFIX + transferId + ":" + receiverId);
        boolean isLocked = false;
        try {
            // 尝试加锁，使用配置的时间和单位
            isLocked = lock.tryLock(lockWaitTime, lockLeaseTime, lockTimeUnit);
            if (!isLocked) {
                log.warn("用户：[ {} ] 领取转账：[ {} ] 时，尝试加锁失败！", receiverId, transferId);
                return Result.custom(CoReturnFormat.FAIL, "系统繁忙，请稍后再试!");
            }

            // 判断转账订单状态和剩余数量
            TransferOrder transferOrder = transferOrderMapper.selectById(transferId);
            if (transferOrder == null) {
                return Result.custom(CoReturnFormat.FAIL, "transferId为: " + transferId + "的转账订单不存在!");
            }
            BigDecimal receiveAmount = transferOrder.getActualAmount();
            if (!StringUtils.equals(transferOrder.getReceiverId(), receiverId)) {
                return Result.custom(CoReturnFormat.FAIL, "不是您的转账订单，不能领取!");
            }
            if (!TransferOrderStatusEnum.PENDING_RECEIVED.getCode().equals(transferOrder.getStatus())) {
                log.info("转账订单不是待领取状态，暂时无法领取! transferId: {}", transferId);
                return Result.custom(CoReturnFormat.FAIL, "转账暂时无法领取!");
            }
            // 查询用户是否已领取过该转账订单
            LambdaQueryWrapper<TransferReceiveRecord> queryRecordWrapper = new QueryWrapper<TransferReceiveRecord>().lambda()
                    .eq(TransferReceiveRecord::getTransferId, transferId)
                    .eq(TransferReceiveRecord::getReceiverId, receiverId);
            int recordCount = transferReceiveRecordMapper.selectCount(queryRecordWrapper);
            if (recordCount > 0) {
                return Result.custom(CoReturnFormat.FAIL, "您已领取转账，请勿重复领取!");
            }

            // 修改转账订单状态
            LocalDateTime nowTime = LocalDateTime.now();
            transferOrder.setStatus(TransferOrderStatusEnum.COMPLETED.getCode());
            transferOrder.setReceiveTime(nowTime);
            transferOrder.setCompletedTime(nowTime);
            int updated = transferOrderMapper.updateById(transferOrder);
            if (updated < 1) {
                log.info("修改转账订单状态失败, transferId: {}", transferId);
                throw new BusinessException("领取失败，请重试");
            }

            // 保存转账订单领取记录
            TransferReceiveRecord receiveRecord = transferDTO.coverToTransferReceiveRecord();
            receiveRecord.setAmount(receiveAmount);
            int inserted = transferReceiveRecordMapper.insert(receiveRecord);
            if (inserted < 1) {
                log.info("添加转账订单领取记录失败, transferId: {}", transferId);
                throw new BusinessException("领取失败，请重试");
            }

            // 领取转账成功，增加金额到用户钱包
            String receiveOrderId = "RECEIVE_" + transferId;
            boolean added = timWalletPayService.addWalletBalance(Long.parseLong(receiverId), receiveOrderId, receiveAmount,
                    TransactionTypeEnum.TRANSFER_ORDER_RECEIVE.getCode(), "领取转账后，增加转账金额到用户钱包。");
            if (!added) {
                log.info("添加金额到用户钱包失败, userId: {}, amount: {}", receiverId, receiveAmount);
                throw new BusinessException("领取失败，请重试");
            }

            // 发送修改转账订单历史消息
            boolean modified = modifyTimMsg(transferId);
            if (!modified) {
                log.info("修改转账订单历史消息失败, transferId: {}", transferId);
                throw new BusinessException("领取失败，请重试");
            }
            log.info("用户 [{}] 成功领取转账订单 [{}], 金额: {}", receiverId, transferId, receiveAmount);
            return Result.success(receiveRecord);

        } catch (InterruptedException e) {
            // 保留中断状态
            Thread.currentThread().interrupt();
            log.error("用户：[ {} ] 领取转账：[ {} ] 时，加锁等待被中断！", receiverId, transferId, e);
            return Result.custom(CoReturnFormat.FAIL, "领取失败，请稍后重试！");
        } catch (Exception e) {
            log.error("用户：[ {} ] 领取转账：[ {} ] 时，发生未预期异常！", receiverId, transferId, e);
            return Result.custom(CoReturnFormat.FAIL, "领取失败，请稍后重试！");
        } finally {
            // 在 finally 块中确保锁被释放
            if (isLocked && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.debug("用户 [{}] 领取转账 [{}] 后，锁已释放", receiverId, transferId);
            }
        }
    }

    @Override
    public boolean modifyTimMsg(String transferId) {
        // 查询最新的红包信息
        TransferOrder transferOrder = transferOrderMapper.selectById(transferId);
        CustomMsgData msgData = transferOrder.covertToCustomMsgData();
        MsgRequestDTO requestDTO = transferOrder.covertToMsgRequestDTO();
        requestDTO.setMsgKey(transferOrder.getMsgKey());
        requestDTO.setMsgId(transferOrder.getMsgId());
        requestDTO.setMsgSeq(transferOrder.getMsgSeq());
        TIMBaseResponse response;
        if (StringUtils.isNotBlank(transferOrder.getGroupId())) {
            response = timMsgService.modifyGroupMsg(MsgTypeEnum.CUSTOM, msgData, requestDTO);
        } else {
            response = timMsgService.modifyC2cMsg(MsgTypeEnum.CUSTOM, msgData, requestDTO);
        }
        return ActionStatus.OK.getStatus().equals(response.getActionStatus());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean refund(String transferId, int refundType) {
        LocalDateTime nowTime = LocalDateTime.now();
        // 查询转账订单
        LambdaQueryWrapper<TransferOrder> queryWrapper = new QueryWrapper<TransferOrder>().lambda()
                .eq(TransferOrder::getTransferId, transferId);
        TransferOrder transferOrder = transferOrderMapper.selectOne(queryWrapper);
        if (transferOrder == null) {
            log.info("转账：[{}] 不存在！", transferId);
            return false;
        }
        // 自动退款的，判断订单是否过期
        if (RefundTypeEnum.EXPIRED.getCode().equals(refundType) && transferOrder.getExpireTime().isAfter(nowTime)) {
            log.info("转账：[{}] 未过期，不用退还至用户钱包余额！", transferId);
            return false;
        }

        BigDecimal refundAmount = transferOrder.getActualAmount();
        log.info("用户：[{}] 发出的转账：[{}] 过期，退还至用户钱包余额", transferOrder.getSenderId(), transferId);
        // 退款至用户钱包余额，并记录交易流水
        String refundOrderNo = "REFUND_" + transferId;
        boolean added = timWalletPayService.addWalletBalance(Long.valueOf(transferOrder.getSenderId()), refundOrderNo, refundAmount,
                TransactionTypeEnum.TRANSFER_ORDER_REFUND.getCode(), "转账退款,转账单号：" + transferId);

        transferOrder.setStatus(TransferOrderStatusEnum.REFUNDED.getCode());
        transferOrder.setRefundTime(nowTime);
        transferOrder.setRefundType(refundType);
        transferOrder.setCompletedTime(nowTime);
        int updated = transferOrderMapper.updateById(transferOrder);
        if (added && updated > 0) {
            TransferRefundRecord refundRecord = TransferRefundRecord.builder()
                   .transferId(transferId)
                   .refundOrderId(refundOrderNo)
                   .refundType(refundType)
                   .amount(refundAmount)
                   .refundTime(nowTime)
                   .build();
            int insert = transferRefundRecordMapper.insert(refundRecord);
            if (insert < 1) {
                log.error("添加转账订单：[{}] 退款记录失败！", transferId);
                return false;
            }
            log.info("用户：[{}] 发出的转账：[{}] 退款成功，退款金额：[{}] ", transferOrder.getSenderId(), transferId, refundAmount);
            return true;
        }
        log.error("用户：[{}] 发出的转账：[{}] 退款失败", transferOrder.getSenderId(), transferId);
        return false;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Object> refundByUser(TransferOrderDTO transferDTO) {
        String transferId = transferDTO.getTransferId();
        boolean refund = refund(transferId, RefundTypeEnum.USER_HANDLE.getCode());
        if (refund) {
            // 修改发送给腾讯IM的转账历史消息
            modifyTimMsg(transferId);
            return Result.success();
        } else {
            log.error("转账退款失败: {}", transferId);
            return Result.custom(CoReturnFormat.FAIL, "系统繁忙，请稍后再试!");
        }
    }

    @Override
    public Result<TransferOrderDetailVO> detail(String transferId) {
        TransferOrder transferOrder = transferOrderMapper.selectById(transferId);
        if (transferOrder == null) {
            return Result.custom(CoReturnFormat.FAIL, "转账订单不存在!");
        }
        LambdaQueryWrapper<TransferReceiveRecord> queryWrapper = new QueryWrapper<TransferReceiveRecord>().lambda()
                .eq(TransferReceiveRecord::getTransferId, transferId);
        TransferReceiveRecord record = transferReceiveRecordMapper.selectOne(queryWrapper);

        TransferOrderDetailVO detailVO = new TransferOrderDetailVO();
        detailVO.setTransferOrder(transferOrder.covertToVO());
        detailVO.setReceiveRecord(record);
        return Result.success(detailVO);
    }

    @Override
    public List<TransferOrder> getExpiredTransferOrders() {
        return transferOrderMapper.getExpiredTransferOrders();
    }

}
